package chat

import (
	"baokaobang/datasourse"
	"baokaobang/models"
	"baokaobang/utils"
	"encoding/json"
	"fmt"
	"github.com/go-xorm/xorm"
	gorilla "github.com/gorilla/websocket"
	"github.com/kataras/iris/v12/websocket"
	"github.com/kataras/neffos"
	irisGorilla "github.com/kataras/neffos/gorilla"
	"log"
	"net/http"
	"sync"
	"time"
)

var (
	ConnMap  map[string]*neffos.Conn
	GroupMap map[string]map[string]bool
	rwLock   sync.RWMutex
)

func init() {
	ConnMap = map[string]*neffos.Conn{}
	GroupMap = map[string]map[string]bool{}
}

type ResMsg struct {
	Uid        string `json:"uid"`        // 当前登录用户id
	Sid        string `json:"sid"`        // 当前登录用户token
	MType      int    `json:"type"`       // 消息类型 0心跳 1登录 2单聊消息 3群消息
	To         string `json:"to"`         // 要发送给谁
	Content    string `json:"content"`    // 消息内容
	Timestamp  int64  `json:"timestamp"`  // 消息发送时间戳
	IsShowTime int    `json:"isShowTime"` // 是否显示时间 0不显示 1显示，两条消息发送间隔超过5分钟则显示时间
}

type SendMsg struct {
	Uid        string `json:"uid"`        // 发送人id
	Name       string `json:"name"`       // 发送人名字
	Avatar     string `json:"avatar"`     // 发送人头像
	Identity   int    `json:"identity"`   // 发送人身份
	MType      int    `json:"type"`       // 消息类型 0心跳 1登录 2单聊消息 3群消息
	To         string `json:"to"`         // 要发送给谁
	Content    string `json:"content"`    // 消息内容
	Timestamp  int64  `json:"timestamp"`  // 消息发送时间戳
	IsShowTime int    `json:"isShowTime"` // 是否显示时间，0不显示 1显示，两条消息发送间隔超过5分钟则显示时间
	IsSelf     int    `json:"isSelf"`     // 是否是自己发的消息，0不是 1是
}

func GetWs() *neffos.Server {
	u := irisGorilla.Upgrader(gorilla.Upgrader{CheckOrigin: func(r *http.Request) bool {
		return true
	}})

	ws := websocket.New(u, websocket.Events{
		websocket.OnNativeMessage: func(nsConn *websocket.NSConn, msg websocket.Message) error {
			resMsg := ResMsg{}
			err := json.Unmarshal(msg.Body, &resMsg)
			if err != nil {
				fmt.Printf("解析消息出错：%s\n", err.Error())
				return nil
			}
			fmt.Println(resMsg)

			if resMsg.MType == 0 {
				mg := websocket.Message{
					Body:     msg.Body,
					IsNative: true,
				}
				nsConn.Conn.Write(mg)
				return nil
			}

			if resMsg.MType == 1 {
				db, err := datasourse.NewMasterOrm()
				if err != nil {
					fmt.Printf("无法连接数据库：%s\n", err.Error())
					nsConn.Conn.Close()
					return nil
				}

				user := new(models.User)
				ok, _ := db.Where("id = ? and token = ?", resMsg.Uid, resMsg.Sid).Get(user)
				if !ok {
					fmt.Printf("用户未登录\n")
					nsConn.Conn.Close()
					return nil
				}

				go genGroup(nsConn, db, user)

				mg := websocket.Message{
					Body:     msg.Body,
					IsNative: true,
				}
				nsConn.Conn.Write(mg)
				return nil
			}

			if resMsg.MType == 2 {
				conn, ok := ConnMap[resMsg.To]
				if ok {
					db, err := datasourse.NewMasterOrm()
					if err != nil {
						fmt.Printf("无法连接数据库：%s\n", err.Error())
						nsConn.Conn.Close()
						return nil
					}

					sendUser := new(models.User)
					_, err = db.ID(resMsg.Uid).Get(sendUser)
					if err != nil {
						fmt.Printf("查询发送人信息出错：%s\n", err.Error())
						return nil
					}

					name := ""
					if sendUser.UserType == 1 {
						name = sendUser.Name
					} else if sendUser.UserType == 2 {
						college := new(models.CollegeData)
						_, err = db.ID(sendUser.CollegeId).Get(college)
						if err != nil {
							fmt.Printf("查询发送人院校信息出错：%s\n", err.Error())
							return nil
						}
						name = fmt.Sprintf("%s(%s)", college.Name, sendUser.ShortName)
					} else if sendUser.UserType == 3 {
						name = fmt.Sprintf("一对一专家(%s)", sendUser.ShortName)
					} else if sendUser.UserType == 4 {
						name = fmt.Sprintf("辅导员(%s)", sendUser.ShortName)
					}

					sendMsg := SendMsg{
						Uid:        resMsg.Uid,
						Name:       name,
						Avatar:     sendUser.Avatar,
						Identity:   sendUser.UserType,
						MType:      resMsg.MType,
						To:         resMsg.To,
						Content:    resMsg.Content,
						Timestamp:  resMsg.Timestamp,
						IsShowTime: resMsg.IsShowTime,
						IsSelf:     0,
					}
					content, err := json.Marshal(sendMsg)
					if err != nil {
						return nil
					}

					mg := websocket.Message{
						Body:     content,
						IsNative: true,
					}
					conn.Write(mg)
				}
			}

			if resMsg.MType == 3 {
				db, err := datasourse.NewMasterOrm()
				if err != nil {
					fmt.Printf("无法连接数据库：%s\n", err.Error())
					nsConn.Conn.Close()
					return nil
				}

				sendUser := new(models.User)
				_, err = db.ID(resMsg.Uid).Get(sendUser)
				if err != nil {
					fmt.Printf("查询发送人信息出错：%s\n", err.Error())
					return nil
				}

				name := ""
				if sendUser.UserType == 1 {
					name = sendUser.Name
				} else if sendUser.UserType == 2 {
					college := new(models.College)
					_, err = db.ID(sendUser.CollegeId).Get(college)
					if err != nil {
						fmt.Printf("查询发送人院校信息出错：%s\n", err.Error())
						return nil
					}
					name = fmt.Sprintf("%s(%s)", college.Name, sendUser.ShortName)
				} else if sendUser.UserType == 3 {
					name = fmt.Sprintf("一对一专家(%s)", sendUser.ShortName)
				} else if sendUser.UserType == 4 {
					name = fmt.Sprintf("辅导员(%s)", sendUser.ShortName)
				}
				//fmt.Println(name)
				//fmt.Println(GroupMap)

				for uid, _ := range GroupMap[resMsg.To] {
					conn, ok := ConnMap[uid]
					fmt.Println(ok)
					if ok {
						sendMsg := SendMsg{
							Uid:        resMsg.Uid,
							Name:       name,
							Avatar:     sendUser.Avatar,
							Identity:   sendUser.UserType,
							MType:      resMsg.MType,
							To:         resMsg.To,
							Content:    resMsg.Content,
							Timestamp:  resMsg.Timestamp,
							IsShowTime: resMsg.IsShowTime,
							IsSelf:     0,
						}
						content, err := json.Marshal(sendMsg)
						if err != nil {
							fmt.Printf("消息序列化失败：%s\n", err.Error())
							return nil
						}

						mg := websocket.Message{
							Body:     content,
							IsNative: true,
						}
						result := conn.Write(mg)
						if result {
							fmt.Println("发送成功")
							fmt.Println(string(content))
						} else {
							fmt.Println("发送失败")
							fmt.Println(string(content))
						}
					}
				}
			}

			return nil
		},
	})

	ws.OnConnect = func(c *websocket.Conn) error {
		ctx := websocket.GetContext(c)
		uid := ctx.URLParam("uid")
		fmt.Println(fmt.Sprintf("连接：%s", uid))
		rwLock.Lock()
		ConnMap[uid] = c
		rwLock.Unlock()
		return nil
	}

	ws.OnDisconnect = func(c *websocket.Conn) {
		ctx := websocket.GetContext(c)
		uid := ctx.URLParam("uid")
		fmt.Println(fmt.Sprintf("断开：%s", uid))
		rwLock.RLock()
		delete(ConnMap, uid)
		rwLock.RUnlock()
	}

	ws.OnUpgradeError = func(err error) {
		log.Printf("Upgrade Error: %v", err)
	}

	return ws
}

// 生成群聊map
func genGroup(nsConn *websocket.NSConn, db *xorm.Engine, user *models.User) {
	var err error

	if user.UserType == 1 { // 学生
		year := utils.Atoi(time.Now().Format("2006"))
		matchCollegeList := make([]models.MatchCollege, 0)
		if user.TestScore > 0 {
			err = db.Where("is_test = 1 and year = ? and score = ? and user_id = ? and is_buy_ensure_admission = ?", year, user.TestScore, user.Id, user.IsBuyEnsureAdmission).Find(&matchCollegeList)
		} else {
			err = db.Where("is_test = 0 and year = ? and score = ? and user_id = ? and is_buy_ensure_admission = ?", year, user.SimulateScore, user.Id, user.IsBuyEnsureAdmission).Find(&matchCollegeList)
		}
		if err != nil {
			nsConn.Conn.Close()
			return
		}

		for _, matchCollege := range matchCollegeList {
			k := fmt.Sprintf("%d", matchCollege.CollegeId)
			rwLock.Lock()
			if len(GroupMap[k]) <= 0 {
				GroupMap[k] = map[string]bool{}
			}
			ke := fmt.Sprintf("%d", user.Id)
			GroupMap[k][ke] = true // 将自己加入到群组
			rwLock.Unlock()
		}
	} else if user.UserType == 2 { // 招办老师
		k := fmt.Sprintf("%d", user.CollegeId)
		rwLock.Lock()
		if len(GroupMap[k]) <= 0 {
			GroupMap[k] = map[string]bool{}
		}
		ke := fmt.Sprintf("%d", user.Id)
		GroupMap[k][ke] = true // 将自己加入到群组
		rwLock.Unlock()
	}
}
